home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / ExportWAVSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  12.5 KB  |  402 lines  |  [TEXT/KAHL]

  1. /* ExportWAVSample.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "ExportWAVSample.h"
  31. #include "SampleConsts.h"
  32. #include "SampleStorageActual.h"
  33. #include "Memory.h"
  34. #include "Files.h"
  35. #include "Alert.h"
  36. #include "BufferedFileOutput.h"
  37.  
  38.  
  39. /* prototype for the function that actually does the work. */
  40. static MyBoolean        TryToExportWAVFile(BufferedOutputRec* File,
  41.                                             SampleStorageActualRec* Sample, long SamplingRate);
  42.  
  43.  
  44. /* this routine saves the data in the provided sample storage object as a WAVE */
  45. /* formatted file.  it handles any error reporting to the user.  the object is */
  46. /* NOT disposed, so the caller has to do that. */
  47. void                                ExportWAVSample(struct SampleStorageActualRec* TheSample,
  48.                                             long SamplingRate)
  49.     {
  50.         FileSpec*                    WhereToSave;
  51.  
  52.         CheckPtrExistence(TheSample);
  53.         WhereToSave = PutFile("Untitled.WAV");
  54.         if (WhereToSave != NIL)
  55.             {
  56.                 if (CreateFile(WhereToSave,CODE4BYTES('?','?','?','?'),
  57.                     CODE4BYTES('?','?','?','?')))
  58.                     {
  59.                         FileType*                    TheFileDescriptor;
  60.  
  61.                         if (OpenFile(WhereToSave,&TheFileDescriptor,eReadAndWrite))
  62.                             {
  63.                                 BufferedOutputRec*    BufferedFileThing;
  64.  
  65.                                 BufferedFileThing = NewBufferedOutput(TheFileDescriptor);
  66.                                 if (BufferedFileThing != NIL)
  67.                                     {
  68.                                         (void)TryToExportWAVFile(BufferedFileThing,TheSample,SamplingRate);
  69.                                         EndBufferedOutput(BufferedFileThing);
  70.                                     }
  71.                                  else
  72.                                     {
  73.                                         AlertHalt("There is not enough memory available to export "
  74.                                             "the file.",NIL);
  75.                                     }
  76.                                 CloseFile(TheFileDescriptor);
  77.                             }
  78.                          else
  79.                             {
  80.                                 AlertHalt("Unable to open the file for writing.",NIL);
  81.                             }
  82.                     }
  83.                  else
  84.                     {
  85.                         AlertHalt("The file could not be created.",NIL);
  86.                     }
  87.                 DisposeFileSpec(WhereToSave);
  88.             }
  89.     }
  90.  
  91.  
  92. /* RIFF file format, with WAVE information */
  93. /*  'RIFF' */
  94. /*  4-byte little endian length descriptor (minus 8 bytes for these 2 fields) */
  95. /*  'WAVE' */
  96. /*  'fmt ' */
  97. /*  4-byte little endian length descriptor for the 'fmt ' header block */
  98. /*      - this should be 16.  if not, then it's some other kind of WAV file */
  99. /*  2-byte little endian format descriptor.  this is always here. */
  100. /*      - 1 = PCM */
  101. /*  2-byte little endian number of channels. */
  102. /*  4-byte little endian sampling rate integer. */
  103. /*  4-byte little endian average bytes per second. */
  104. /*  2-byte little endian block align.  for 8-bit mono, this is 1; for 16-bit */
  105. /*    stereo, this is 4. */
  106. /*  2-byte little endian number of bits. */
  107. /*      - 8 = 8-bit */
  108. /*      - 16 = 16-bit */
  109. /*  'data' */
  110. /*  4-byte little endian length of sample data descriptor */
  111. /*  any length data.  8-bit data goes from 0..255, but 16-bit data goes */
  112. /*    from -32768 to 32767. */
  113. static MyBoolean        TryToExportWAVFile(BufferedOutputRec* File,
  114.                                             SampleStorageActualRec* Sample, long SamplingRate)
  115.     {
  116.         unsigned long            TotalSampleLength;
  117.         unsigned long            TotalChunkLength;
  118.         unsigned long            BytesPerSecond;
  119.         unsigned short        BlockAlignment;
  120.  
  121.         CheckPtrExistence(File);
  122.         CheckPtrExistence(Sample);
  123.  
  124.         /*  'RIFF' */
  125.         if (!WriteBufferedOutput(File,4,"RIFF"))
  126.             {
  127.              DiskErrorPoint:
  128.                 AlertHalt("A file error occurred and the sample couldn't be exported.",NIL);
  129.                 return False;
  130.             }
  131.  
  132.         /* figure out how long chunk will be */
  133.         switch (GetSampleStorageActualNumBits(Sample))
  134.             {
  135.                 default:
  136.                     EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  137.                         "GetSampleStorageActualNumBits"));
  138.                     break;
  139.                 case eSample8bit:
  140.                     switch (GetSampleStorageActualNumChannels(Sample))
  141.                         {
  142.                             default:
  143.                                 EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  144.                                     "GetSampleStorageActualNumBits"));
  145.                                 break;
  146.                             case eSampleMono:
  147.                                 TotalSampleLength = GetSampleStorageActualNumFrames(Sample) * 1;
  148.                                 BytesPerSecond = SamplingRate * 1;
  149.                                 BlockAlignment = 1;
  150.                                 break;
  151.                             case eSampleStereo:
  152.                                 TotalSampleLength = GetSampleStorageActualNumFrames(Sample) * 2;
  153.                                 BytesPerSecond = SamplingRate * 2;
  154.                                 BlockAlignment = 2;
  155.                                 break;
  156.                         }
  157.                     break;
  158.                 case eSample16bit:
  159.                     switch (GetSampleStorageActualNumChannels(Sample))
  160.                         {
  161.                             default:
  162.                                 EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  163.                                     "GetSampleStorageActualNumBits"));
  164.                                 break;
  165.                             case eSampleMono:
  166.                                 TotalSampleLength = GetSampleStorageActualNumFrames(Sample) * 2;
  167.                                 BytesPerSecond = SamplingRate * 2;
  168.                                 BlockAlignment = 2;
  169.                                 break;
  170.                             case eSampleStereo:
  171.                                 TotalSampleLength = GetSampleStorageActualNumFrames(Sample) * 4;
  172.                                 BytesPerSecond = SamplingRate * 4;
  173.                                 BlockAlignment = 4;
  174.                                 break;
  175.                         }
  176.                     break;
  177.             }
  178.         TotalChunkLength = TotalSampleLength + 36;
  179.  
  180.         /*  4-byte little endian length descriptor (minus 8 bytes for these 2 fields) */
  181.         if (!WriteBufferedUnsignedLongLittleEndian(File,TotalChunkLength))
  182.             {
  183.                 goto DiskErrorPoint;
  184.             }
  185.  
  186.         /*  'WAVE' */
  187.         /*  'fmt ' */
  188.         if (!WriteBufferedOutput(File,8,"WAVEfmt "))
  189.             {
  190.                 goto DiskErrorPoint;
  191.             }
  192.  
  193.         /*  4-byte little endian length descriptor for the 'fmt ' header block */
  194.         /*      - this should be 16.  if not, then it's some other kind of WAV file */
  195.         if (!WriteBufferedUnsignedLongLittleEndian(File,16))
  196.             {
  197.                 goto DiskErrorPoint;
  198.             }
  199.  
  200.         /*  2-byte little endian format descriptor.  this is always here. */
  201.         /*      - 1 = PCM */
  202.         if (!WriteBufferedUnsignedShortLittleEndian(File,1))
  203.             {
  204.                 goto DiskErrorPoint;
  205.             }
  206.  
  207.         /*  2-byte little endian number of channels. */
  208.         switch (GetSampleStorageActualNumChannels(Sample))
  209.             {
  210.                 default:
  211.                     EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  212.                         "GetSampleStorageActualNumBits"));
  213.                     break;
  214.                 case eSampleMono:
  215.                     if (!WriteBufferedUnsignedShortLittleEndian(File,1))
  216.                         {
  217.                             goto DiskErrorPoint;
  218.                         }
  219.                     break;
  220.                 case eSampleStereo:
  221.                     if (!WriteBufferedUnsignedShortLittleEndian(File,2))
  222.                         {
  223.                             goto DiskErrorPoint;
  224.                         }
  225.                     break;
  226.             }
  227.  
  228.         /*  4-byte little endian sampling rate integer. */
  229.         if (!WriteBufferedUnsignedLongLittleEndian(File,SamplingRate))
  230.             {
  231.                 goto DiskErrorPoint;
  232.             }
  233.  
  234.         /*  4-byte little endian average bytes per second. */
  235.         if (!WriteBufferedUnsignedLongLittleEndian(File,BytesPerSecond))
  236.             {
  237.                 goto DiskErrorPoint;
  238.             }
  239.  
  240.         /*  2-byte little endian block align.  for 8-bit mono, this is 1; for 16-bit */
  241.         /*    stereo, this is 4. */
  242.         if (!WriteBufferedUnsignedShortLittleEndian(File,BlockAlignment))
  243.             {
  244.                 goto DiskErrorPoint;
  245.             }
  246.  
  247.         /*  2-byte little endian number of bits. */
  248.         /*      - 8 = 8-bit */
  249.         /*      - 16 = 16-bit */
  250.         switch (GetSampleStorageActualNumBits(Sample))
  251.             {
  252.                 default:
  253.                     EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  254.                         "GetSampleStorageActualNumBits"));
  255.                     break;
  256.                 case eSample8bit:
  257.                     if (!WriteBufferedUnsignedShortLittleEndian(File,8))
  258.                         {
  259.                             goto DiskErrorPoint;
  260.                         }
  261.                     break;
  262.                 case eSample16bit:
  263.                     if (!WriteBufferedUnsignedShortLittleEndian(File,16))
  264.                         {
  265.                             goto DiskErrorPoint;
  266.                         }
  267.                     break;
  268.             }
  269.  
  270.         /*  'data' */
  271.         if (!WriteBufferedOutput(File,4,"data"))
  272.             {
  273.                 goto DiskErrorPoint;
  274.             }
  275.  
  276.         /*  4-byte little endian length of sample data descriptor */
  277.         if (!WriteBufferedUnsignedLongLittleEndian(File,TotalSampleLength))
  278.             {
  279.                 goto DiskErrorPoint;
  280.             }
  281.  
  282.         /*  any length data.  8-bit data goes from 0..255, but 16-bit data goes */
  283.         /*    from -32768 to 32767. */
  284.         switch (GetSampleStorageActualNumBits(Sample))
  285.             {
  286.                 default:
  287.                     EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  288.                         "GetSampleStorageActualNumBits"));
  289.                     break;
  290.                 case eSample8bit:
  291.                     switch (GetSampleStorageActualNumChannels(Sample))
  292.                         {
  293.                             default:
  294.                                 EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  295.                                     "GetSampleStorageActualNumBits"));
  296.                                 break;
  297.                             case eSampleMono:
  298.                                 {
  299.                                     long                        Limit;
  300.                                     long                        Scan;
  301.  
  302.                                     Limit = GetSampleStorageActualNumFrames(Sample);
  303.                                     for (Scan = 0; Scan < Limit; Scan += 1)
  304.                                         {
  305.                                             largefixedsigned        SampleWord;
  306.  
  307.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eMonoChannel);
  308.                                             if (!WriteBufferedUnsignedChar(File,
  309.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT) + 128))
  310.                                                 {
  311.                                                     goto DiskErrorPoint;
  312.                                                 }
  313.                                         }
  314.                                 }
  315.                                 break;
  316.                             case eSampleStereo:
  317.                                 {
  318.                                     long                        Limit;
  319.                                     long                        Scan;
  320.  
  321.                                     Limit = GetSampleStorageActualNumFrames(Sample);
  322.                                     for (Scan = 0; Scan < Limit; Scan += 1)
  323.                                         {
  324.                                             largefixedsigned        SampleWord;
  325.  
  326.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eLeftChannel);
  327.                                             if (!WriteBufferedUnsignedChar(File,
  328.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT) + 128))
  329.                                                 {
  330.                                                     goto DiskErrorPoint;
  331.                                                 }
  332.  
  333.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eRightChannel);
  334.                                             if (!WriteBufferedUnsignedChar(File,
  335.                                                 roundtonearest(largefixed2double(SampleWord) * MAX8BIT) + 128))
  336.                                                 {
  337.                                                     goto DiskErrorPoint;
  338.                                                 }
  339.                                         }
  340.                                 }
  341.                                 break;
  342.                         }
  343.                     break;
  344.                 case eSample16bit:
  345.                     switch (GetSampleStorageActualNumChannels(Sample))
  346.                         {
  347.                             default:
  348.                                 EXECUTE(PRERR(ForceAbort,"TryToExportWAVFile:  bad value from "
  349.                                     "GetSampleStorageActualNumBits"));
  350.                                 break;
  351.                             case eSampleMono:
  352.                                 {
  353.                                     long                        Limit;
  354.                                     long                        Scan;
  355.  
  356.                                     Limit = GetSampleStorageActualNumFrames(Sample);
  357.                                     for (Scan = 0; Scan < Limit; Scan += 1)
  358.                                         {
  359.                                             largefixedsigned        SampleWord;
  360.  
  361.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eMonoChannel);
  362.                                             if (!WriteBufferedSignedShortLittleEndian(File,
  363.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  364.                                                 {
  365.                                                     goto DiskErrorPoint;
  366.                                                 }
  367.                                         }
  368.                                 }
  369.                                 break;
  370.                             case eSampleStereo:
  371.                                 {
  372.                                     long                        Limit;
  373.                                     long                        Scan;
  374.  
  375.                                     Limit = GetSampleStorageActualNumFrames(Sample);
  376.                                     for (Scan = 0; Scan < Limit; Scan += 1)
  377.                                         {
  378.                                             largefixedsigned        SampleWord;
  379.  
  380.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eLeftChannel);
  381.                                             if (!WriteBufferedSignedShortLittleEndian(File,
  382.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  383.                                                 {
  384.                                                     goto DiskErrorPoint;
  385.                                                 }
  386.  
  387.                                             SampleWord = GetSampleStorageActualValue(Sample,Scan,eRightChannel);
  388.                                             if (!WriteBufferedSignedShortLittleEndian(File,
  389.                                                 roundtonearest(largefixed2double(SampleWord) * MAX16BIT)))
  390.                                                 {
  391.                                                     goto DiskErrorPoint;
  392.                                                 }
  393.                                         }
  394.                                 }
  395.                                 break;
  396.                         }
  397.                     break;
  398.             }
  399.  
  400.         return True;
  401.     }
  402.